For every javascript to be able to communicate with the shiny server the
following has to be included, and all the rest of the code goes inside it.

#+BEGIN_SRC javascript :noweb yes :tangle ../www/scatterplot.js
Shiny.addCustomMessageHandler("scatterplot_values", function(message) {

    <<data treatment>>
    <<plot>>
    <<brush>>
    <<the rest>>

});
#+END_SRC

#+BEGIN_SRC javascript
var dataset = message;
#+END_SRC

The data we get from R is a two dimensional array of strings, positions of the
form dataset[i][0] contain a time string in the form of a 4 digit number
representing a time in a 24 hour clock, for instance "0700" would be
representing 07:00. Javascript works with /Date/ objects so we define two
functions, the first parseTime will convert a string of the form explained above
to a /Date/ object. The other function formatTime will serve to print this object
properly later. Now a simply loop through the dataset will parse all the time
strings.

#+NAME: data treatment
#+BEGIN_SRC javascript
var dataset = message;

var parseTime = d3.timeParse("%H%M");
var formatTime = d3.timeFormat("%H:%M");

for (i = 0; i < dataset.length; i++) {
    dataset[i][0] = parseTime(dataset[i][0]);
}
#+END_SRC

We have to define the size of the area that will hold our
plot. The total area is given by width and height variables,
but inside it we will define a plot area, that is an area
inside the svg element offset by the margins.

#+NAME: plot
#+BEGIN_SRC javascript
var margin = {top: 20, right: 50, bottom: 50, left: 85},
    width = 600,
    height = 500,
    plot_width = width - margin.right - margin.left,
    plot_height = height - margin.top - margin.bottom;
#+END_SRC

First element in the array is of the type /Date/ so we have to use a time scale,
the second element is number (actually a string that will be parsed to a number
automatically) so we use a linear scale. The third element is a string
describing the type of accident and is not used now.

#+NAME: the rest
#+BEGIN_SRC javascript
var xScale = d3.scaleTime()
    .domain(d3.extent(dataset, function(d) { return (d[0]); }))
    .range([margin.left, plot_width]);

var yScale = d3.scaleLinear()
    .domain(d3.extent(dataset, function(d) { return d[1]; }))
    .range([plot_height, margin.top]);
#+END_SRC

We define two functions to create the axes of the graph, the X axis will be
bellow the graphic and Y to the left of it. The function tickFormat receives a a
function as argument that defines explicitely the formatting of the data
appearing in an axis, here we pass the [[data treatment][formatTime]] function defined previously.

#+NAME: the rest
#+BEGIN_SRC javascript
var axis_x = d3.axisBottom(xScale)
    .tickFormat(formatTime);
var axis_y = d3.axisLeft(yScale);
#+END_SRC

Now we create an svg element where the visualization will be created. Following
the project /coding style/ there is a /div/ named #scatterplot_area that will
contain the svg, it is selected with d3.select and the svg is element is
appended to it, we use the toal area (width e height), not only the plot area as
the svg will also contain other graphic elements, like the axes.

#+NAME: plot
#+BEGIN_SRC javascript
var scatterplot = d3.select("#scatterplot_area")
    .append("svg")
    .attr("width", width)
    .attr("height", height);
#+END_SRC

Now we create a group for the plot points, each point receives
an initial id of /points/.

Using the defined variable for the plot points we bind our dataset
to svg circles, assigning a class of /point/ to each circle and
updating the id to the form of points-i, where i is a simple
index from 0 to the dataset length - 1. The coordinates of
the circles are given by the hour of the accident(d[0])
and the age of the victimn(d[1]).

#+NAME: the rest
#+BEGIN_SRC javascript
var points = scatterplot.append("g").attr("id", "points");

// Criar círculos
points.selectAll("circle")
    .data(dataset)
    .enter()
    .append("circle")
    .attr("class", "point")
    .attr("id", function(d, i) {
	return "point-" + i;
    })
    .attr("r", 3)
    .attr("cx", function(d) {
	return xScale(d[0]);
    })
    .attr("cy", function(d) {
	return yScale(d[1]);
    });
#+END_SRC

Finally, after the graph is done we draw the axes.

#+NAME: the rest
#+BEGIN_SRC javascript
scatterplot.append("g")
    .attr("id", "axis_x")
    .attr("transform", "translate(0," + (plot_height + margin.bottom / 2) + ")")
    .call(axis_x);

scatterplot.append("g")
    .attr("id", "axis_y")
    .attr("transform", "translate(" + (margin.left / 2) + ", 0)")
    .call(axis_y);

d3.select("#axis_x")
    .append("text")
    .attr("transform", "translate(420, -5)")
    .text("Hora");

d3.select("#axis_y")
    .append("text")
    .attr("transform", "rotate(-90) translate(-20, 15)")
    .text("Idade");
#+END_SRC

For this scatterplot we are using a third-party library called polybrush, it has
the same API as d3's brush module, but works very differently, it enables
polygonal brush selections, the first major difference is during instatiation we
have to pass x and y values that define the area that it will work. The start
interaction beggins with a click, it resets the selected class of all points.
For the brush interaction itself we pass a function that will highlight the
brushed circles, and on the end interaction another functions will display some
information of the selected circles in a table.

#+NAME: brush
#+BEGIN_SRC javascript
var brush = d3.polybrush()
    .x(d3.scaleLinear().range([margin.left / 2, width]))
    .y(d3.scaleLinear().range([margin.top / 2, height]))
    .on("start", function() {
	scatterplot.selectAll(".selected").classed("selected", false);
    })
    .on("brush", highlightBrushedPoints)
    .on("end", displayTable);
#+END_SRC

#+NAME: brush
#+BEGIN_SRC javascript
scatterplot.append("g")
    .attr("class", "brush")
    .call(brush);

function clearTableRows() {

    hideTableColNames();
    d3.selectAll(".row_data").remove();
}

function hideTableColNames() {
    d3.select("table").style("visibility", "hidden");
}

function showTableColNames() {
    d3.select("table").style("visibility", "visible");
}

function highlightBrushedPoints() {

    scatterplot.selectAll(".point").classed("selected", function(d) {
        //get the associated circle
        var id = d3.select(this).attr("id");
        var i = id.substr(id.indexOf("-") + 1, id.length);

        if (brush.isWithinExtent(xScale(d[0]), yScale(d[1]))) {
            return true;
        } else {
            return false;
        }
    });
}

function displayTable() {

    var d_brushed =  d3.selectAll(".point.selected").data();

    console.log(d_brushed);

    // populate table if one or more elements is brushed
    if (d_brushed.length > 0) {
	clearTableRows();
	d_brushed.forEach(d_row => populateTableRow(d_row));
    } else {
	clearTableRows();
    }
}

function populateTableRow(d_row) {

    showTableColNames();

    var d_row_filter = [d_row[2], // Agente Causador
                        formatTime(d_row[0]), // Hora
                        d_row[1]]; //Idade

    d3.select("table")
        .append("tr")
        .attr("class", "row_data")
        .selectAll("td")
        .data(d_row_filter)
        .enter()
        .append("td")
        .attr("align", (d, i) => i == 0 ? "left" : "right")
        .text(d => d);
}
#+END_SRC
